#include "OBJ.h"

std::map<std::string, Material> creteMaterials(const char * path)
{
	std::map<std::string, Material> materials;
	
	std::string currentMat;
	Material tempMat;

	std::string p = "data/models/";
	p.append(path);

	printf("Loading mtl file %s...\n", p.c_str());

	FILE * file = fopen(p.c_str(), "r");
	if( file == NULL ){
		printf("Impossible to open the file !\n");
		return materials;
	}

	while( 1 ){

		char lineHeader[200];
		// read the first word of the line
		int res = fscanf(file, "%s", lineHeader);
		if (res == EOF)
			break; // EOF = End Of File. Quit the loop.

		// else : parse lineHeader
		if(strcmp(lineHeader, "newmtl") == 0) {
			//process mtl file and create materials for it
			char temp[128];
			fscanf(file, "%s \n", &temp );
			currentMat = temp;
			tempMat.name = currentMat;
			materials[currentMat] = tempMat;
		}else if(strcmp(lineHeader, "Ns") == 0)
		{
			float temp;
			fscanf(file, "%f \n", &temp );
			materials[currentMat].Shinies = temp;
			
		}else if(strcmp(lineHeader, "Ka") == 0)
		{
			glm::vec3 tmp;
			fscanf(file, "%f %f %f\n", &tmp.x, &tmp.y, &tmp.z );
			materials[currentMat].AmbiantColor = tmp;

		}else if(strcmp(lineHeader, "Kd") == 0)
		{
			glm::vec3 tmp;
			fscanf(file, "%f %f %f\n", &tmp.x, &tmp.y, &tmp.z );
			materials[currentMat].DifuseColor= tmp;
		
		}else if(strcmp(lineHeader, "Ks") == 0)
		{
			glm::vec3 tmp;
			fscanf(file, "%f %f %f\n", &tmp.x, &tmp.y, &tmp.z );
			materials[currentMat].SpecularColor = tmp;
		}else if(strcmp(lineHeader, "map_Ka") == 0)
		{
			char tmp[128];
			fscanf(file, "%s \n", &tmp);

			std::string t = "data/";
			t.append(tmp);

			materials[currentMat].AmbientTexture =  loadTGA_glfw(t.c_str());
			

		}else if(strcmp(lineHeader, "map_Kd") == 0)
		{
			char tmp[128];
			fscanf(file, "%s \n", &tmp);

			std::string t = "data/";
			t.append(tmp);

			materials[currentMat].DifuseTexture =  loadTGA_glfw(t.c_str());
			

		}else if(strcmp(lineHeader, "map_bump") == 0)
		{
			char tmp[128];
			fscanf(file, "%s \n", &tmp);

			std::string t = "data/";
			t.append(tmp);


			materials[currentMat].NormalTexture =  loadTGA_glfw(t.c_str());

		}else{
			// Probably a comment, eat up the rest of the line
			char stupidBuffer[1000];
			fgets(stupidBuffer, 1000, file);
		}
	}

	return materials;
}

bool loadOBJ(const char * path, std::map<std::string, subMesh>& subMeshes){
	printf("Loading OBJ file %s...\n", path);

	//create temporary storage for all submeshes
	std::map<std::string, subMesh> tempSubMeshes;


	//temporary mesh name 
	char subMeshName[128];

	//create temporary storage for all materials
	std::map<std::string, Material> temMaterials;
	
	std::map<std::string, std::vector<unsigned int>> vertexIndices, uvIndices, normalIndices;
	std::vector<glm::vec3> temp_vertices; 
	std::vector<glm::vec2> temp_uvs;
	std::vector<glm::vec3> temp_normals;


	FILE * file = fopen(path, "r");
	if( file == NULL ){
		printf("Impossible to open the file !\n");
		return false;
	}

	while( 1 ){

		char lineHeader[200];
		// read the first word of the line
		int res = fscanf(file, "%s", lineHeader);
		if (res == EOF)
			break; // EOF = End Of File. Quit the loop.

		// else : parse lineHeader
		if(strcmp(lineHeader, "mtllib") == 0) {
			//process mtl file and create materials for it
			char temp[128];
			fscanf(file, "%s \n", &temp );
			temMaterials = creteMaterials(temp);
		}

		if ( strcmp( lineHeader, "v" ) == 0 ){
			glm::vec3 vertex;
			fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z );
			temp_vertices.push_back(vertex);
		}else if ( strcmp( lineHeader, "vt" ) == 0 ){
			glm::vec2 uv;
			fscanf(file, "%f %f\n", &uv.x, &uv.y );
			temp_uvs.push_back(uv);
		}else if ( strcmp( lineHeader, "vn" ) == 0 ){
			glm::vec3 normal;
			fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z );
			temp_normals.push_back(normal);
		}else if (strcmp(lineHeader, "usemtl") ==0 ){
			fscanf(file, "%s \n", &subMeshName);

			subMesh tmp;
			
			tmp.material = temMaterials[subMeshName];
			
			tempSubMeshes[subMeshName] = tmp;

		}else if ( strcmp( lineHeader, "f" ) == 0 ){
			std::string vertex1, vertex2, vertex3;
			unsigned int vertexIndex[4], uvIndex[4], normalIndex[4];
			int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2], &vertexIndex[3], &uvIndex[3], &normalIndex[3] );
			if (matches == 9){
				vertexIndices[subMeshName].push_back(vertexIndex[0]);
				vertexIndices[subMeshName].push_back(vertexIndex[1]);
				vertexIndices[subMeshName].push_back(vertexIndex[2]);
				uvIndices[subMeshName]    .push_back(uvIndex[0]);
				uvIndices[subMeshName]    .push_back(uvIndex[1]);
				uvIndices[subMeshName]    .push_back(uvIndex[2]);
				normalIndices[subMeshName].push_back(normalIndex[0]);
				normalIndices[subMeshName].push_back(normalIndex[1]);
				normalIndices[subMeshName].push_back(normalIndex[2]);

			}else if(matches == 12)
			{
				vertexIndices[subMeshName].push_back(vertexIndex[0]);
				vertexIndices[subMeshName].push_back(vertexIndex[1]);
				vertexIndices[subMeshName].push_back(vertexIndex[2]);
				vertexIndices[subMeshName].push_back(vertexIndex[3]);
				uvIndices[subMeshName]    .push_back(uvIndex[0]);
				uvIndices[subMeshName]    .push_back(uvIndex[1]);
				uvIndices[subMeshName]    .push_back(uvIndex[2]);
				uvIndices[subMeshName]    .push_back(uvIndex[3]);
				normalIndices[subMeshName].push_back(normalIndex[0]);
				normalIndices[subMeshName].push_back(normalIndex[1]);
				normalIndices[subMeshName].push_back(normalIndex[2]);
				normalIndices[subMeshName].push_back(normalIndex[3]);

			}
			else {
				printf("File can't be read by our simple parser :-( Try exporting with other options\n");
				return false;

			}
		}else{
			// Probably a comment, eat up the rest of the line
			char stupidBuffer[1000];
			fgets(stupidBuffer, 1000, file);
		}

	}

	// For each vertex of each triangle
	std::map<std::string, subMesh>::iterator iter = tempSubMeshes.begin();
    for(;iter != tempSubMeshes.end(); iter++)
    {
		for( unsigned int i=0; i<vertexIndices[iter->first].size(); i++ ){

			// Get the indices of its attributes
			unsigned int vertexIndex = vertexIndices[iter->first][i];
			unsigned int uvIndex = uvIndices[iter->first][i];
			unsigned int normalIndex = normalIndices[iter->first][i];
		
			// Get the attributes thanks to the index
			glm::vec3 vertex = temp_vertices[ vertexIndex-1 ];
			glm::vec2 uv = temp_uvs[ uvIndex-1 ];
			glm::vec3 normal = temp_normals[ normalIndex-1 ];
		
			iter->second.vertices.push_back(vertex);
			iter->second.uvs.push_back(uv);
			iter->second.normals.push_back(normal);
		}
	
	}

	subMeshes = tempSubMeshes;
	return true;
}
